/*
 * #%L
 * SwiftUICommonUtilities
 * $Id:$
 * $HeadURL:$
 * %%
 * Copyright (C) 2011 - 2012 Linkwithweb
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */
/**
 * 
 */
package com.linkwithweb.products.swiftui.utils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.linkwithweb.products.swiftui.context.SystemContext;

import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.FileTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.StringTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.cache.WebappTemplateLoader;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.Configuration;
import freemarker.template.ObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;

/**
 * This Class Acts Like Utility Class For Freemarker Evaluation
 * 
 * @author ashwin
 * 
 */
public class FreeMarkerEngine {
	private static final transient Log logger = LogFactory
			.getLog(FreeMarkerEngine.class);

	private static FreeMarkerEngine freeMarkerEngine = new FreeMarkerEngine();

	Configuration cfg = null;
	Configuration strcfg = null;

	/**
	 * Default Parameters to be set before passing to freemarker processing
	 */
	Map defaultParams = new HashMap();

	FileTemplateLoader ftl1 = null;
	ClassTemplateLoader ctl = null;
	WebappTemplateLoader wtl = null;

	MultiTemplateLoader mtl = null;
	TemplateLoader[] loaders = null;

	// Making this private to create singleton class
	private FreeMarkerEngine() {
		cfg = new Configuration();
		strcfg = new Configuration();
		// Specify the data source where the template files come from.
		// Here I set a file directory for it:
		try {
			// Default is FTL Directory
			cfg.setDirectoryForTemplateLoading(new File("ftl"));
			ftl1 = new FileTemplateLoader(new File("ftl"));
			
			//strcfg.setDirectoryForTemplateLoading(new File("ftl"));

		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.debug("Default Directory ftl not found" + e);
		}

		try {
			ctl = new ClassTemplateLoader(getClass(), "");

		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.debug("Default Directory ftl not found" + e);
		}

		try {
			wtl = new WebappTemplateLoader(SystemContext.getInstance()
					.getServletContext(), "WEB-INF/spring");

		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.debug("Default Directory ftl not found" + e);
		}

		setFileLoaders();

		cfg.setTemplateLoader(mtl);

		// Specify how templates will see the data-model. This is an advanced
		// topic...
		// but just use this:
		// cfg.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
		// scfg.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX);

		// Specify how templates will see the data-model. This is an advanced
		// topic...
		// but just use this:
		cfg.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
		BeansWrapper bw = (BeansWrapper) cfg.getObjectWrapper();
		bw.setSimpleMapWrapper(true);
		bw.setExposureLevel(BeansWrapper.EXPOSE_ALL);
		cfg.setObjectWrapper(bw);
		cfg.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX);
		
		
		strcfg.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
		BeansWrapper strbw = (BeansWrapper) strcfg.getObjectWrapper();
		strbw.setSimpleMapWrapper(true);
		strbw.setExposureLevel(BeansWrapper.EXPOSE_ALL);
		strcfg.setObjectWrapper(strbw);
		strcfg.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX);

		// Setting Default Parameters
		defaultParams.put("GlobalContext", SystemContext.getInstance());

	}

	/**
	 * @param directoryPath
	 */
	public void changeFTLDirectory(String directoryPath) {
		// Specify the data source where the template files come from.
		// Here I set a file directory for it:
		try {
			cfg.setDirectoryForTemplateLoading(new File(directoryPath));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			logger.debug(e);
		}
	}

	/**
	 * @return
	 */
	public static FreeMarkerEngine getInstance() {
		return freeMarkerEngine;
	}

	/**
	 * @param template
	 * @return
	 */
	public String evaluateString(String template) {
		Map parameters = new HashMap();
		parameters.putAll(getInstance().defaultParams);
		return evaluateString(template, parameters);
	}

	/**
	 * @param template
	 * @return
	 */
	public String evaluateString(String evauationTemplate, Map parameters) {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		OutputStreamWriter output = new OutputStreamWriter(bos);
		StringTemplateLoader stringLoader = new StringTemplateLoader();
		String stringTemplate = "stringTemplate";
		stringLoader.putTemplate(stringTemplate, evauationTemplate);
		strcfg.setTemplateLoader(stringLoader);
		try {
			Template template = strcfg.getTemplate(stringTemplate);
			parameters.putAll(getInstance().defaultParams);
			template.process(parameters, output);
		} catch (IOException e) {
			// logger.debug(e);
			return null;
		} catch (TemplateException e) {
			//logger.debug(e);
			return null;
		}  catch (Throwable th) {
			//logger.debug(th);
			return null;
		}

		return bos.toString();

	}

	/**
	 * @param fileName
	 * @return
	 */
	public String evaluateTemplate(String fileName) {
		Map parameters = new HashMap();
		parameters.putAll(getInstance().defaultParams);
		return evaluateTemplate(fileName, parameters);
	}

	/**
	 * 
	 */
	private void setFileLoaders() {
		try {

			if (ftl1 == null) {
				loaders = new TemplateLoader[] { wtl, ctl };
			} else {
				loaders = new TemplateLoader[] { ftl1, ctl };
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.debug("Default Directory ftl not found" + e);
		}

		try {
			mtl = new MultiTemplateLoader(loaders);

		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.debug("Default Directory ftl not found" + e);
		}
		cfg.setTemplateLoader(mtl);
	}

	/**
	 * @param fileName
	 * @param Parameters
	 * @return
	 */
	public String evaluateTemplate(String fileName, Map parameters) {
		// setFileLoaders();
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		OutputStreamWriter output = new OutputStreamWriter(bos);
		parameters.putAll(getInstance().defaultParams);
		try {
			Template tpl = cfg.getTemplate(fileName);
			tpl.process(parameters, output);

		} catch (java.io.FileNotFoundException e) {
			// Incase of Error try loading from template page
			try {
				Template tpl = cfg.getTemplate("template/" + fileName);
				tpl.process(parameters, output);
			} catch (Throwable th) {
				// Incase there is Exception in FileREading then REturn Blank
				logger.debug(th);
				// Incase of Error Return the same Template
				try {
					String returnStr = FileUtils.readFileToString(new File(
							fileName));
					return returnStr;
				} catch (Throwable th2) {
					// Incase there is Exception in FileREading then REturn
					// Blank
					logger.debug(th2);
					return "";
				}
			}
		} catch (Throwable e) {
			logger.debug(e);
			return "";
		}

		return bos.toString();
	}

	/**
	 * @param fileName
	 * @param Parameters
	 * @return
	 */
	public String evaluateTemplate(String fileName, Map parameters,
			boolean canLoadDefault) {
		// setFileLoaders();
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		OutputStreamWriter output = new OutputStreamWriter(bos);
		try {
			Template tpl = cfg.getTemplate(fileName);
			tpl.process(parameters, output);

		} catch (java.io.FileNotFoundException e) {
			// Incase of Error try loading from template page
			try {
				if (canLoadDefault) {
					String[] fileNameStrings = fileName.split("_");
					Template tpl = cfg.getTemplate(fileNameStrings[0]
							+ fileNameStrings[fileNameStrings.length - 1]);
					tpl.process(parameters, output);
				} else {
					Template tpl = cfg.getTemplate("template/" + fileName);
					tpl.process(parameters, output);
				}
			} catch (Throwable th) {
				// Incase there is Exception in FileREading then REturn Blank
				logger.debug(th);
				// Incase of Error Return the same Template
				try {
					String returnStr = FileUtils.readFileToString(new File(
							fileName));
					return returnStr;
				} catch (Throwable th2) {
					// Incase there is Exception in FileREading then REturn
					// Blank
					logger.debug(th2);
					return "";
				}
			}
		} catch (Throwable e) {
			logger.debug(e);
			return "";
		}

		return bos.toString();
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		List mediaFileList = new ArrayList();

		Map rootMap = new HashMap();
		rootMap.put("list", mediaFileList);
		rootMap.putAll(getInstance().defaultParams);

		logger.debug(freeMarkerEngine.evaluateTemplate("Freemarker.ftl",
				rootMap));
	}

}
